package wang.lxl.concurrent.threadPool;

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.*;

/**
 * 一, 线程池: 提供了一个线程队列,队列中保存着等待状态的线程,避免了频繁的创建和销毁线程造成的额外开销,提高了相应速度.
 * 二, 线程池体系结构:
 * java.util.concurrent.Executor: 负责线程使用与调度的根接口
 *   |-- **ExecutorService 子接口 : 线程池的主要接口
 *      |-- ThreadPoolExecutor 线程池的实现类
 *      |-- ScheduledExecutorService 子接口: 负责线程的调度
 *          |-- ScheduledThreadPoolExecutor : 继承 ThreadPoolExecutor,实现ScheduledExecutorService
 *
 *  三,工具类: Executors
 *  ExecutorService  newFixedThreadPool(); : 创建固定大小的线程池(等待线程的队列的最大值为int的最大值)
 *  ExecutorService  newCachedThreadPool(); : 缓存线程池,线程池中的线程数量不固定,可以根据需求自动的更改数量.(线程的最大数量为int的最大值)
 *  ExecutorService  newSingleThreadPool();  : 创建单个线程的线程池,池中只有一个线程.
 *
 *  ScheduledExecutorService  newScheduledThreadPool(); : 创建固定大小的线程,可以延迟或定时的执行任务.
 */
public class ThreadPoolDemo {
    /**
     * 项目中通常是直接创建ThreadPoolExecutor的实例,参数详解如下
     * public ThreadPoolExecutor(int corePoolSize,//核心线程数,即使空闲也保留在线程中的线程数,除非设置allowCoreThreadTimeOut
     *                                             // CPU核数 = Runtime.getRuntime().availableProcessors();
     *                                             // (一般配置规律:CPU密集型：核心线程数 = CPU核数 + 1,IO密集型：核心线程数 = CPU核数 * 2)
     *                               int maximumPoolSize,// 池中允许的最大线程数
     *                               long keepAliveTime,// 当线程数大于内核时,这是多余的空闲线程在终止前等待新任务的最大的时间
     *                               TimeUnit unit,// keepAliveTime的时间单位
     *                               BlockingQueue<Runnable> workQueue,// 用于在执行任务之前使用的队列,这个队列将仅保存execute方法提交的Runnable任务
     *                               ThreadFactory threadFactory,// 执行程序创建新线程时使用的工厂(通常用来给线程赋名称值)
     *                               RejectedExecutionHandler handler);// 线程拒绝策略(达到线程限制或队列已满)
     *
     */
    /*
    接下来说说线程池的拒绝策略  :
    JDK实现的拒绝有四种:
        1, AbortPolicy : 该策略会直接抛异常,阻止系统正常工作
        2,CallerRunsPolcy: 如果线程池已经关闭则丢弃当前任务,只要线程池没有关闭,就直接在execute方法的调用线程中运行被拒绝的任务,
            虽然减少了任务丢弃的几率,但是任务提交线程的性能将很可能急剧下降.
        3,DiscardOldestPolicy: 如果线程池已经关闭则丢弃当前任务,否则就丢弃最旧的未处理的任务,然后重试execute方法.
        4,DiscardPolicy: 默默的丢弃没法处理的任务,如果允许线程任务丢失则可采用该拒绝策略.
     最后还有一种自定义的拒绝策略
        5,自定义的拒绝策略: 实现RejectedExecutionHandler接口 并重写其中的rejectedExecution()方法.参数r为任务线程,executor为当前线程池.

    (默认拒绝策略源码如下)
    //The default rejected execution handler
    private static final RejectedExecutionHandler defaultHandler =
            new AbortPolicy();
     线程池的默认拒绝策略为  AbortPolicy
     */
    public static void main(String[] args) throws Exception{
        // 测试调度线程池
        ScheduledExecutorService excutor = Executors.newScheduledThreadPool(4);
        ArrayList<ScheduledFuture<Integer>> futures = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            ScheduledFuture<Integer> schedule = excutor.schedule(() -> {
                int num = new Random().nextInt(100);
                System.out.println(Thread.currentThread().getName()+" : "+num);
                return num;
            }, 1, TimeUnit.SECONDS);// 延迟一秒执行任务
            futures.add(schedule);
        }
        excutor.shutdown();// 以平和的方式关闭线程池(等池中的线程执行完毕之后再关闭线程池)
//        excutor.shutdownNow()// 暴力关闭线程池
        for (ScheduledFuture<Integer> future : futures) {
            System.out.println(future.get());
        }
    }
}
